package helper

import (
	"cgs-server/internal/cgserver/global"
	"fmt"
	"github.com/spf13/viper"
	"os"
	"runtime"
	"strings"

	"github.com/BurntSushi/toml"
)

const (
	PublicRelease  = "PUBLIC"
	PrivateRelease = "PRIVATE"
)

// GetConfig read toml format file `config.toml`, and parse ConfigModel.
//
// See: https://github.com/toml-lang/toml
func GetConfig(path string) (config *ConfigModel, err error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	defer file.Close()

	if _, err = toml.DecodeReader(file, &config); err != nil {
		return nil, err
	}

	// parse mongoDB connection string.
	if config.Database.User != "" && config.Database.Password != "" {
		// If user is empty, this will cause `error parsing uri: authsource without username is invalid` error.
		config.Database.Connection = fmt.Sprintf(
			"mongodb://%v:%v@%v:%v",
			config.Database.User,
			config.Database.Password,
			config.Database.Host,
			config.Database.Port,
		)
	} else {
		config.Database.Connection = fmt.Sprintf(
			"mongodb://%v:%v",
			config.Database.Host,
			config.Database.Port,
		)
	}

	// In windows system, path separator "/" should be replace with "\\".
	if strings.HasPrefix(runtime.GOOS, "windows") {
		config.Path.PublicDir = strings.ReplaceAll(config.Path.PublicDir, "/", "\\")
		config.Path.LogDir = strings.ReplaceAll(config.Path.LogDir, "/", "\\")
	}

	// 检查短信密钥，私有版需要配置自己的密钥
	if config.Version.ReleaseType == PrivateRelease {
		// 如果是私有版，不允许使用 [畅图云] 签名
		if config.Sms.SignName == "畅图云" {
			config.Sms.clear()
		}
		// 私有版暂时关闭使用公有的 bimface 账号
		config.Bimface.AppSecret = ""
		config.Bimface.AppSecret = ""
	}

	return
}

func SetConfig() (config *ConfigModel, err error) {

	config = &ConfigModel{
		Server: ServerConfigModel{
			Port: viper.GetString("insecure.bind-port"),
			Host: viper.GetString("insecure.bind-address"),
		},
		Database: DatabaseConfigModel{
			Host:     viper.GetString("mongo.host"),
			Port:     viper.GetInt("mongo.port"),
			Database: viper.GetString("mongo.database"),
			User:     viper.GetString("mongo.user"),
			Password: viper.GetString("mongo.password"),
		},
		Authority: AuthorityConfigModel{
			Enabled:   true,
			Expires:   120,
			SecretKey: viper.GetString("jwt.key"),
		},
		Upload: UploadConfigModel{
			MaxSize:      100 << 20, // 100MB
			ModelMaxSize: 15 << 20,  // 15MB
		},
		Remote: RemoteConfigModel{
			Enabled:       true,
			WebSocketPort: 5000,
		},
		Path: PathConfigModel{
			PublicDir: viper.GetString("path.public-dir"),
			LogDir:    "./build/logs",
		},
		Log: LogConfigModel{
			File: viper.GetString("log.output-paths"),
		},
		Sms: SmsConfigModel{
			AccessKeyId:               "",
			AccessKeySecret:           "",
			SignName:                  "畅图云",
			VerificationTemplateCode:  "SMS_217936310",
			VerificationTemplateParam: "code",
		},
		Version: VersionModel{
			Version:     global.Version,
			ReleaseType: global.ReleaseType,
		},
		Bimface: BimfaceModel{
			AppKey:    "",
			AppSecret: "",
		},
	}

	// parse mongoDB connection string.
	if config.Database.User != "" && config.Database.Password != "" {
		// If user is empty, this will cause `error parsing uri: authsource without username is invalid` error.
		config.Database.Connection = fmt.Sprintf(
			"mongodb://%v:%v@%v:%v/?authSource=%v",
			config.Database.User,
			config.Database.Password,
			config.Database.Host,
			config.Database.Port,
			config.Database.AuthSource,
		)
	} else {
		config.Database.Connection = fmt.Sprintf(
			"mongodb://%v:%v",
			config.Database.Host,
			config.Database.Port,
		)
	}

	// In windows system, path separator "/" should be replace with "\\".
	if strings.HasPrefix(runtime.GOOS, "windows") {
		config.Path.PublicDir = strings.ReplaceAll(config.Path.PublicDir, "/", "\\")
		config.Path.LogDir = strings.ReplaceAll(config.Path.LogDir, "/", "\\")
	}

	// 检查短信密钥，私有版需要配置自己的密钥
	if config.Version.ReleaseType == PrivateRelease {
		// 如果是私有版，不允许使用 [畅图云] 签名
		if config.Sms.SignName == "畅图云" {
			config.Sms.clear()
		}
		// 私有版暂时关闭使用公有的 bimface 账号
		config.Bimface.AppSecret = ""
		config.Bimface.AppSecret = ""
	}

	return
}

// ConfigModel is the structure of file `config.toml`.
type ConfigModel struct {
	Server    ServerConfigModel    `toml:"server"`
	Database  DatabaseConfigModel  `toml:"database"`
	Authority AuthorityConfigModel `toml:"authority"`
	Upload    UploadConfigModel    `toml:"upload"`
	Remote    RemoteConfigModel    `toml:"remote"`
	Path      PathConfigModel      `toml:"path"`
	Log       LogConfigModel       `toml:"log"`
	Sms       SmsConfigModel       `toml:"sms"`
	Version   VersionModel         `toml:"version"`
	Bimface   BimfaceModel         `toml:"bimface"`
}

// ServerConfigModel is the server config section in `config.toml`.
type ServerConfigModel struct {
	Port string `toml:"port"`
	Host string `toml:"host"`
}

// DatabaseConfigModel is the database config section in `config.toml`.
type DatabaseConfigModel struct {
	Type       string `toml:"type"`
	Host       string `toml:"host"`
	Port       int    `toml:"port"`
	User       string `toml:"user"`
	Password   string `toml:"password"`
	Database   string `toml:"database"`
	AuthSource string `toml:"authSource"`

	// Connection should not read from config.toml.
	Connection string
}

// AuthorityConfigModel is the authority config section in `config.toml`.
type AuthorityConfigModel struct {
	Enabled   bool   `toml:"enabled"`
	Expires   int    `toml:"expires"`
	SecretKey string `toml:"secret_key"`
}

// UploadConfigModel is the upload config section in `config.toml`.
type UploadConfigModel struct {
	MaxSize      int64 `toml:"max_size"`
	ModelMaxSize int64 `toml:"model_max_size"`
}

// RemoteConfigModel is the remote config section in `config.toml`.
type RemoteConfigModel struct {
	Enabled       bool `toml:"enabled"`
	WebSocketPort int  `toml:"web_socket_port"`
}

// PathConfigModel is the authority path section in `config.toml`.
type PathConfigModel struct {
	PublicDir string `toml:"public_dir"`
	LogDir    string `toml:"log_dir"`
}

// LogConfigModel is the log config section in `config.toml`.
type LogConfigModel struct {
	File string `toml:"file"`
}

// SmsConfigModel is the sms config section in `config.toml`.
type SmsConfigModel struct {
	AccessKeyId               string `toml:"access_key_id"`
	AccessKeySecret           string `toml:"access_key_secret"`
	SignName                  string `toml:"sign_name"`
	VerificationTemplateCode  string `toml:"verification_template_code"`  // 验证码模板 ID
	VerificationTemplateParam string `toml:"verification_template_param"` // 验证码模板变量名
}

func (s *SmsConfigModel) clear() {
	s.AccessKeyId = ""
	s.AccessKeySecret = ""
	s.SignName = ""
	s.VerificationTemplateCode = ""
	s.VerificationTemplateParam = ""
}

type VersionModel struct {
	Version     string `toml:"version" json:"version"`
	ReleaseType string `toml:"release_type" json:"releaseType"`
}

type BimfaceModel struct {
	AppKey    string `toml:"app_key" json:"app_key"`
	AppSecret string `toml:"app_secret" json:"app_secret"`
}
